package cn.hamster3.mc.plugin.core.common.data;

import cn.hamster3.mc.plugin.core.common.util.CoreUtils;
import com.google.gson.JsonObject;
import lombok.Getter;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextReplacementConfig;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.title.Title;
import net.kyori.adventure.util.Ticks;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@SuppressWarnings({"unused", "UnusedReturnValue", "PatternValidation"})
@Getter
public class DisplayMessage {
    private Component message;
    private Component actionbar;
    private Title title;
    /**
     * <a href="https://minecraft.fandom.com/zh/wiki/Sounds.json">点击查看 minecraft 所有声音资源</a>
     */
    private Sound sound;

    public DisplayMessage() {
    }

    @NotNull
    public static DisplayMessage fromJson(@NotNull JsonObject object) {
        DisplayMessage displayMessage = new DisplayMessage();
        if (object.has("message")) {
            displayMessage.message = GsonComponentSerializer.gson().deserializeFromTree(object.get("message")).compact();
        }
        if (object.has("actionbar")) {
            displayMessage.actionbar = GsonComponentSerializer.gson().deserializeFromTree(object.get("actionbar")).compact();
        }
        if (object.has("title")) {
            displayMessage.title = CoreUtils.deserializeTitle(object.getAsJsonObject("title"));
        }
        if (object.has("sound")) {
            displayMessage.sound = CoreUtils.deserializeSound(object.getAsJsonObject("sound"));
        }
        return displayMessage;
    }

    public void show(@NotNull Audience audience, @NotNull TextReplacementConfig... replacements) {
        Component replacedMessage = message;
        Component replacedActionbar = actionbar;
        Title replacedTitle = title;
        for (TextReplacementConfig replacement : replacements) {
            if (replacedMessage != null) {
                replacedMessage = replacedMessage.replaceText(replacement);
            }
            if (replacedActionbar != null) {
                replacedActionbar = replacedActionbar.replaceText(replacement);
            }
            if (replacedTitle != null) {
                replacedTitle = Title.title(
                        replacedTitle.title().replaceText(replacement).compact(),
                        replacedTitle.subtitle().replaceText(replacement).compact(),
                        replacedTitle.times()
                );
            }
        }
        if (replacedMessage != null) {
            audience.sendMessage(replacedMessage);
        }
        if (replacedActionbar != null) {
            audience.sendActionBar(replacedActionbar);
        }
        if (replacedTitle != null) {
            audience.showTitle(replacedTitle);
        }
        if (sound != null) {
            audience.playSound(sound);
        }
    }

    @NotNull
    public DisplayMessage setMessage(@NotNull String message) {
        this.message = Component.text(message);
        return this;
    }

    @NotNull
    public DisplayMessage setMessage(@Nullable Component message) {
        this.message = message;
        return this;
    }

    @NotNull
    public DisplayMessage setActionbar(@NotNull String actionbar) {
        this.actionbar = Component.text(actionbar);
        return this;
    }

    @NotNull
    public DisplayMessage setActionbar(@NotNull Component actionbar) {
        this.actionbar = actionbar;
        return this;
    }

    @NotNull
    public DisplayMessage setTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int stay, int fadeOut) {
        this.title = Title.title(
                title == null ? Component.empty() : Component.text(title),
                subtitle == null ? Component.empty() : Component.text(subtitle),
                Title.Times.times(
                        Ticks.duration(fadeIn),
                        Ticks.duration(stay),
                        Ticks.duration(fadeOut)
                )
        );
        return this;
    }

    @NotNull
    public DisplayMessage setTitle(@Nullable Component title, @Nullable Component subtitle, int fadeIn, int stay, int fadeOut) {
        this.title = Title.title(
                title == null ? Component.empty() : title,
                subtitle == null ? Component.empty() : subtitle,
                Title.Times.times(
                        Ticks.duration(fadeIn),
                        Ticks.duration(stay),
                        Ticks.duration(fadeOut)
                )
        );
        return this;
    }

    @NotNull
    public DisplayMessage setTitle(@Nullable Title title) {
        this.title = title;
        return this;
    }

    @NotNull
    public DisplayMessage setSound(@NotNull String sound, float volume, float pitch) {
        this.sound = Sound.sound(Key.key(sound), Sound.Source.MASTER, volume, pitch);
        return this;
    }

    @NotNull
    public DisplayMessage setSound(@NotNull String namespace, @NotNull String value, float volume, float pitch) {
        this.sound = Sound.sound(Key.key(namespace, value), Sound.Source.MASTER, volume, pitch);
        return this;
    }

    @NotNull
    public DisplayMessage setSound(@NotNull String namespace, @NotNull String value, @NotNull Sound.Source source, float volume, float pitch) {
        this.sound = Sound.sound(Key.key(namespace, value), source, volume, pitch);
        return this;
    }

    @NotNull
    public DisplayMessage setSound(@Nullable Sound sound) {
        this.sound = sound;
        return this;
    }

    @NotNull
    public DisplayMessage replace(@NotNull TextReplacementConfig... replacements) {
        DisplayMessage copy = copy();
        if (copy.message != null) {
            for (TextReplacementConfig replacement : replacements) {
                copy.message = copy.message.replaceText(replacement).compact();
            }
        }
        if (copy.actionbar != null) {
            for (TextReplacementConfig replacement : replacements) {
                copy.actionbar = copy.actionbar.replaceText(replacement).compact();
            }
        }
        if (copy.title != null) {
            for (TextReplacementConfig replacement : replacements) {
                copy.title = Title.title(
                        title.title().replaceText(replacement).compact(),
                        title.subtitle().replaceText(replacement).compact(),
                        title.times()
                );
            }
        }
        return copy;
    }

    @NotNull
    public DisplayMessage replace(@NotNull String key, String value) {
        return replace(TextReplacementConfig.builder().matchLiteral(key).replacement(value).build());
    }

    @NotNull
    public JsonObject toJson() {
        JsonObject object = new JsonObject();
        if (message != null) {
            object.add("message", GsonComponentSerializer.gson().serializeToTree(message));
        }
        if (actionbar != null) {
            object.add("actionbar", GsonComponentSerializer.gson().serializeToTree(actionbar));
        }
        if (title != null) {
            object.add("title", CoreUtils.serializeTitle(title));
        }
        if (sound != null) {
            object.add("sound", CoreUtils.serializeSound(sound));
        }
        return object;
    }

    @NotNull
    public DisplayMessage copy() {
        DisplayMessage copy = new DisplayMessage();
        copy.message = message;
        copy.actionbar = actionbar;
        copy.title = title;
        copy.sound = sound;
        return copy;
    }

    @Override
    public String toString() {
        return toJson().toString();
    }
}
